<template>
  <el-container class="form-designer-designer" :style="'height:' + dragHeight">
    <el-main>
      <el-container style="height: 100%">
        <el-aside class="form-designer-l" width="266px">
          <template v-for="(item, index) in menuList" :key="index">
            <div class="form-designer-l-group">
              <h4 class="form-designer-l-title">{{ item.title }}</h4>
              <draggable :group="{ name: 'default', pull: 'clone', put: false }" :sort="false" itemKey="name"
                :list="item.list">
                <template #item="{ element }">
                  <div class="form-designer-l-item">
                    <div class="form-designer-l-icon">
                      <DynamicIcon :icon="element.icon || 'Box'" />
                    </div>
                    <span class="form-designer-l-name">{{
                      t('components.' + element.name + '.name') || element.label
                    }}</span>
                  </div>
                </template>
              </draggable>
            </div>
          </template>
        </el-aside>
        <el-container class="form-designer-m">
          <el-header class="form-designer-m-tools" height="45">
            <slot name="handle"></slot>
            <el-button type="primary" plain round size="small" @click="previewFc">
              <DynamicIcon icon="View" />
              <span style="margin-left:5px;"> {{ t('designer.preview') }}</span>
            </el-button>
            <el-popconfirm :title="t('designer.clearConfirmTitle')" width="200px"
              :confirm-button-text="t('designer.clearConfirm')" :cancel-button-text="t('designer.clearCancel')"
              @confirm="clearDragRule">
              <template #reference>
                <el-button type="danger" plain round size="small">
                  <DynamicIcon icon="Delete" /> <span style="margin-left:5px;">{{ t('designer.clear') }}</span>
                </el-button>
              </template>
            </el-popconfirm>
          </el-header>
          <el-main style="background: var(--el-color-info-light-9); padding: 20px">
            <div class="form-designer-m-drag">
              <drag-form :rule="dragForm.rule" :option="form.value" v-model:api="dragForm.api"></drag-form>
            </div>
          </el-main>
        </el-container>
        <el-aside class="form-designer-r" width="320px" v-if="!config || config.showConfig !== false">
          <el-container style="height: 100%">
            <el-header height="40px" class="form-designer-r-tabs">
              <div class="form-designer-r-tab" :class="{ active: activeTab === 'props' }"
                v-if="!!activeRule || (config && config.showFormConfig === false)" @click="activeTab = 'props'">
                {{ t('designer.config.component') }}
              </div>
              <div class="form-designer-r-tab" v-if="!config || config.showFormConfig !== false"
                :class="{ active: activeTab === 'form' && !!activeRule }" @click="activeTab = 'form'">
                {{ t('designer.config.form') }}
              </div>
            </el-header>
            <el-main v-show="activeTab === 'form'" v-if="!config || config.showFormConfig !== false">
              <drag-form :rule="form.rule" :option="form.option" v-model="form.value.form"
                v-model:api="form.api"></drag-form>
            </el-main>
            <el-main v-show="activeTab === 'props'" style="padding: 0 20px" :key="activeRule ? activeRule._id : ''">
              <div>
                <el-divider v-if="showBaseRule">{{ t('designer.config.rule') }}</el-divider>
                <drag-form v-show="showBaseRule" v-model:api="baseForm.api" :rule="baseForm.rule"
                  :option="baseForm.options" :modelValue="baseForm.value" @change="baseChange"></drag-form>
                <el-divider>{{ t('designer.config.props') }}</el-divider>
                <drag-form v-model:api="propsForm.api" :rule="propsForm.rule" :option="propsForm.options"
                  :modelValue="propsForm.value" @change="propChange" @removeField="propRemoveField"></drag-form>
                <el-divider v-if="showBaseRule">{{ t('designer.config.validate') }}</el-divider>
                <drag-form v-show="showBaseRule" v-model:api="validateForm.api" :rule="validateForm.rule"
                  :option="validateForm.options" :modelValue="validateForm.value"
                  @update:modelValue="validateChange"></drag-form>
              </div>
            </el-main>
          </el-container>
        </el-aside>
        <el-dialog v-model="preview.state" width="800px" append-to-body>
          <view-form :rule="preview.rule" :option="preview.option" v-if="preview.state"></view-form>
        </el-dialog>
      </el-container>
    </el-main>
  </el-container>
</template>

<style></style>

<script>
import form from '../../config/base/form'
import field from '../../config/base/field'
import validate from '../../config/base/validate'
import { deepCopy } from '@form-create/utils/lib/deepextend'
import is, { hasProperty } from '@form-create/utils/lib/type'
import { lower } from '@form-create/utils/lib/tocase'
import ruleList from '../../config/rule'
import draggable from 'vuedraggable/src/vuedraggable'
import createMenu from '../../config/menu'
import { upper, useLocale } from '../../utils/index'
import { designerForm } from '../../utils/form'
import viewForm from '../../utils/form'
import { t as globalT } from '../../utils/locale'
import {
  computed,
  reactive,
  toRefs,
  toRef,
  ref,
  getCurrentInstance,
  provide,
  nextTick,
  watch,
  defineComponent,
  markRaw
} from 'vue'

export default defineComponent({
  name: 'FormDesigner',
  components: {
    draggable,
    dragForm: designerForm.$form(),
    viewForm: viewForm.$form()
  },
  props: ['menu', 'height', 'config', 'mask', 'locale'],
  setup(props) {
    const { menu, height, mask, locale } = toRefs(props)
    const vm = getCurrentInstance()
    provide('fcx', ref({ active: null }))
    provide('designer', vm)

    const config = toRef(props, 'config', {})
    const baseRule = toRef(config.value, 'baseRule', null)
    const componentRule = toRef(config.value, 'componentRule', {})
    const validateRule = toRef(config.value, 'validateRule', null)
    const formRule = toRef(config.value, 'formRule', null)
    const dragHeight = computed(() => {
      const h = height.value
      if (!h) return '100%'
      return is.Number(h) ? `${h}px` : h
    })
    let _t = globalT
    if (locale.value) {
      _t = useLocale(locale).t
    }
    const t = (...args) => _t(...args)

    const tidyRuleConfig = (orgRule, configRule, ...args) => {
      if (configRule) {
        if (is.Function(configRule)) {
          return configRule(...args)
        }
        if (configRule.rule) {
          let rule = configRule.rule(...args)
          if (configRule.append) {
            rule = [...rule, ...orgRule(...args)]
          }
          return rule
        }
      }
      return orgRule(...args)
    }

    const data = reactive({
      cacheProps: {},
      moveRule: null,
      addRule: null,
      added: null,
      activeTab: 'form',
      activeRule: null,
      children: ref([]),
      menuList: menu.value || createMenu({ t }),
      showBaseRule: false,
      visible: {
        preview: false
      },
      t,
      preview: {
        state: false,
        rule: [],
        option: {}
      },
      dragForm: ref({
        rule: [],
        api: {}
      }),
      form: {
        rule: tidyRuleConfig(form, formRule.value, { t }),
        api: {},
        option: {
          form: {
            labelPosition: 'top',
            size: 'small'
          },
          submitBtn: false
        },
        value: {
          form: {
            inline: false,
            hideRequiredAsterisk: false,
            labelPosition: 'right',
            size: 'small',
            labelWidth: '125px',
            formCreateSubmitBtn: true,
            formCreateResetBtn: false
          },
          submitBtn: false
        }
      },
      baseForm: {
        rule: tidyRuleConfig(field, baseRule.value, { t }),
        api: {},
        value: {},
        options: {
          form: {
            labelPosition: 'top',
            size: 'small'
          },
          submitBtn: false,
          mounted: (fapi) => {
            fapi.activeRule = data.activeRule
            fapi.setValue(fapi.options.formData || {})
          }
        }
      },
      validateForm: {
        rule: tidyRuleConfig(validate, validateRule.value, { t }),
        api: {},
        value: [],
        options: {
          form: {
            labelPosition: 'top',
            size: 'small'
          },
          submitBtn: false,
          mounted: (fapi) => {
            fapi.activeRule = data.activeRule
            fapi.setValue(fapi.options.formData || {})
          }
        }
      },
      propsForm: {
        rule: [],
        api: {},
        value: {},
        options: {
          form: {
            labelPosition: 'top',
            size: 'small'
          },
          submitBtn: false,
          mounted: (fapi) => {
            fapi.activeRule = data.activeRule
            fapi.setValue(fapi.options.formData || {})
          }
        }
      }
    })

    watch(
      () => data.preview.state,
      function (n) {
        if (!n) {
          nextTick(() => {
            data.preview.rule = data.preview.option = null
          })
        }
      }
    )

    let unWatchActiveRule = null

    watch(
      () => locale.value,
      (n) => {
        _t = n ? useLocale(locale).t : globalT
        const formVal = data.form.api.formData && data.form.api.formData()
        const baseFormVal = data.baseForm.api.formData && data.baseForm.api.formData()
        const validateFormVal = data.validateForm.api.formData && data.validateForm.api.formData()
        data.validateForm.rule = tidyRuleConfig(validate, validateRule.value, { t })
        data.baseForm.rule = tidyRuleConfig(field, baseRule.value, { t })
        data.form.rule = tidyRuleConfig(form, formRule.value, { t })
        data.cacheProps = {}
        const rule = data.activeRule
        let propsVal = null
        if (rule) {
          propsVal = data.propsForm.api.formData && data.propsForm.api.formData()
          data.propsForm.rule = data.cacheProps[rule._id] = tidyRuleConfig(
            rule.config.config.props,
            componentRule.value && componentRule.value[rule.config.config.name],
            rule,
            { t, api: data.dragForm.api }
          )
        }
        nextTick(() => {
          formVal && data.form.api.setValue(formVal)
          baseFormVal && data.baseForm.api.setValue(baseFormVal)
          validateFormVal && data.validateForm.api.setValue(validateFormVal)
          propsVal && data.propsForm.api.setValue(propsVal)
        })
      }
    )

    const methods = {
      unWatchActiveRule() {
        unWatchActiveRule && unWatchActiveRule()
        unWatchActiveRule = null
      },
      watchActiveRule() {
        methods.unWatchActiveRule()
        unWatchActiveRule = watch(
          () => data.activeRule,
          function (n) {
            n && methods.updateRuleFormData()
          },
          { deep: true, flush: 'post' }
        )
      },
      makeChildren(children) {
        return reactive({ children }).children
      },
      addMenu(config) {
        if (!config.name || !config.list) return
        let flag = true
        data.menuList.forEach((v, i) => {
          if (v.name === config.name) {
            data.menuList[i] = config
            flag = false
          }
        })
        if (flag) {
          data.menuList.push(config)
        }
      },
      removeMenu(name) {
        ;[...data.menuList].forEach((v, i) => {
          if (v.name === name) {
            data.menuList.splice(i, 1)
          }
        })
      },
      setMenuItem(name, list) {
        data.menuList.forEach((v) => {
          if (v.name === name) {
            v.list = list
          }
        })
      },
      appendMenuItem(name, item) {
        data.menuList.forEach((v) => {
          if (v.name === name) {
            v.list.push(...(Array.isArray(item) ? item : [item]))
          }
        })
      },
      removeMenuItem(item) {
        data.menuList.forEach((v) => {
          let idx
          if (is.String(item)) {
            ;[...v.list].forEach((menu, idx) => {
              if (menu.name === item) {
                v.list.splice(idx, 1)
              }
            })
          } else {
            if ((idx = v.list.indexOf(item)) > -1) {
              v.list.splice(idx, 1)
            }
          }
        })
      },
      addComponent(component) {
        if (Array.isArray(component)) {
          component.forEach((v) => {
            ruleList[v.name] = v
          })
        } else {
          ruleList[component.name] = component
        }
      },
      getParent(rule) {
        let parent = rule.__fc__.parent.rule
        const config = parent.config
        if (config && config.config.inside) {
          rule = parent
          parent = parent.__fc__.parent.rule
        }
        return { root: parent, parent: rule }
      },
      makeDrag(group, tag, children, on) {
        return {
          type: 'DragBox',
          wrap: {
            show: false
          },
          col: {
            show: false
          },
          inject: true,
          props: {
            rule: {
              props: {
                tag: 'el-col',
                group: group === true ? 'default' : group,
                ghostClass: 'ghost',
                animation: 150,
                handle: '._fc-drag-btn',
                emptyInsertThreshold: 0,
                direction: 'vertical',
                itemKey: 'type'
              }
            },
            tag
          },
          children,
          on
        }
      },
      clearDragRule() {
        methods.setRule([])
      },
      makeDragRule(children) {
        return methods.makeChildren([
          methods.makeDrag(true, 'draggable', children, {
            add: (inject, evt) => methods.dragAdd(children, evt),
            end: (inject, evt) => methods.dragEnd(children, evt),
            start: (inject, evt) => methods.dragStart(children, evt),
            unchoose: (inject, evt) => methods.dragUnchoose(children, evt)
          })
        ])
      },
      previewFc() {
        data.preview.state = true
        data.preview.rule = methods.getRule()
        data.preview.option = methods.getOption()
      },
      getRule() {
        return methods.parseRule(deepCopy(data.dragForm.api.rule[0].children))
      },
      getJson() {
        return designerForm.toJson(methods.getRule())
      },
      getOption() {
        const option = deepCopy(data.form.value)
        option.submitBtn = option._submitBtn
        option.resetBtn = option._resetBtn
        if (typeof option.submitBtn === 'object') {
          option.submitBtn.show = option.form.formCreateSubmitBtn
        } else {
          option.submitBtn = {
            show: option.form.formCreateSubmitBtn,
            innerText: t('form.submit')
          }
        }
        if (typeof option.resetBtn === 'object') {
          option.resetBtn.show = option.form.formCreateResetBtn
        } else {
          option.resetBtn = {
            show: option.form.formCreateResetBtn,
            innerText: t('form.reset')
          }
        }
        delete option.form.formCreateSubmitBtn
        delete option.form.formCreateResetBtn
        delete option._submitBtn
        delete option._resetBtn
        return option
      },
      getOptions() {
        methods.getOption()
      },
      setRule(rules) {
        if (!rules) {
          rules = []
        }
        data.children = methods.makeChildren(
          methods.loadRule(is.String(rules) ? designerForm.parseJson(rules) : deepCopy(rules))
        )
        methods.clearActiveRule()
        data.dragForm.rule = methods.makeDragRule(data.children)
      },
      setBaseRuleConfig(rule, append) {
        baseRule.value = { rule, append }
        data.baseForm.rule = tidyRuleConfig(field, baseRule.value, { t })
      },
      setComponentRuleConfig(name, rule, append) {
        componentRule.value[name] = { rule, append }
        data.cacheProps = {}
        const activeRule = data.activeRule
        if (activeRule) {
          const propsVal = data.propsForm.api.formData && data.propsForm.api.formData()
          data.propsForm.rule = data.cacheProps[activeRule._id] = tidyRuleConfig(
            activeRule.config.config.props,
            componentRule.value && componentRule.value[activeRule.config.config.name],
            activeRule,
            { t, api: data.dragForm.api }
          )
          nextTick(() => {
            propsVal && data.propsForm.api.setValue(propsVal)
          })
        }
      },
      setValidateRuleConfig(rule, append) {
        validateRule.value = { rule, append }
        data.validateForm.rule = tidyRuleConfig(field, validateRule.value, { t })
      },
      setFormRuleConfig(rule, append) {
        formRule.value = { rule, append }
        data.form.rule = tidyRuleConfig(field, formRule.value, { t })
      },
      clearActiveRule() {
        data.activeRule = null
        data.activeTab = 'form'
      },
      setOption(opt) {
        let option = { ...opt }
        option.form.formCreateSubmitBtn =
          typeof option.submitBtn === 'object'
            ? option.submitBtn.show === undefined
              ? true
              : !!option.submitBtn.show
            : !!option.submitBtn
        option.form.formCreateResetBtn =
          typeof option.resetBtn === 'object' ? !!option.resetBtn.show : !!option.resetBtn
        option._resetBtn = option.resetBtn
        option.resetBtn = false
        option._submitBtn = option.submitBtn
        option.submitBtn = false
        data.form.value = option
      },
      setOptions(opt) {
        methods.setOption(opt)
      },
      loadRule(rules) {
        const loadRule = []
        rules.forEach((rule) => {
          if (is.String(rule)) {
            return loadRule.push(rule)
          }
          const config = ruleList[rule._fc_drag_tag] || ruleList[rule.type]
          const _children = rule.children
          rule.children = []
          if (rule.control) {
            rule._control = rule.control
            delete rule.control
          }
          if (config) {
            rule = methods.makeRule(config, rule)
            if (_children) {
              let children = rule.children[0].children

              if (config.drag) {
                children = children[0].children
              }
              children.push(...methods.loadRule(_children))
            }
          } else if (_children) {
            rule.children = methods.loadRule(_children)
          }
          loadRule.push(rule)
        })
        return loadRule
      },
      parseRule(children) {
        return [...children].reduce((initial, rule) => {
          if (is.String(rule)) {
            initial.push(rule)
            return initial
          } else if (rule.type === 'DragBox') {
            initial.push(...methods.parseRule(rule.children))
            return initial
          } else if (rule.type === 'DragTool') {
            rule = rule.children[0]
            if (rule.type === 'DragBox') {
              initial.push(...methods.parseRule(rule.children))
              return initial
            }
          }
          if (!rule) return initial
          rule = { ...rule }
          if (rule.children.length) {
            rule.children = methods.parseRule(rule.children)
          }

          delete rule._id
          delete rule.key
          delete rule.component
          if (rule.config) {
            delete rule.config.config
          }
          if (rule.effect) {
            delete rule.effect._fc
            delete rule.effect._fc_tool
          }
          if (rule._control) {
            rule.control = rule._control
            delete rule._control
          }
          Object.keys(rule)
            .filter(
              (k) =>
                (Array.isArray(rule[k]) && rule[k].length === 0) ||
                (is.Object(rule[k]) && Object.keys(rule[k]).length === 0)
            )
            .forEach((k) => {
              delete rule[k]
            })
          initial.push(rule)
          return initial
        }, [])
      },
      baseChange(field, value, _, fapi) {
        if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
          methods.unWatchActiveRule()
          data.activeRule[field] = value
          methods.watchActiveRule()
          data.activeRule.config.config?.watch?.['$' + field]?.({
            field,
            value,
            api: fapi,
            rule: data.activeRule
          })
        }
      },
      propRemoveField(field, _, fapi) {
        if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
          methods.unWatchActiveRule()
          const org = field
          data.dragForm.api.sync(data.activeRule)
          if (field.indexOf('formCreate') === 0) {
            field = field.replace('formCreate', '')
            if (!field) return
            field = lower(field)
            if (field.indexOf('effect') === 0 && field.indexOf('>') > -1) {
              delete data.activeRule.effect[field.split('>')[1]]
            } else if (field.indexOf('props') === 0 && field.indexOf('>') > -1) {
              delete data.activeRule.props[field.split('>')[1]]
            } else if (field.indexOf('attrs') === 0 && field.indexOf('>') > -1) {
              data.activeRule.attrs[field.split('>')[1]] = value
            } else if (field === 'child') {
              delete data.activeRule.children[0]
            } else if (field) {
              data.activeRule[field] = undefined
            }
          } else {
            delete data.activeRule.props[field]
          }
          methods.watchActiveRule()
          data.activeRule.config.config?.watch?.[org]?.({
            field: org,
            value: undefined,
            api: fapi,
            rule: data.activeRule
          })
        }
      },
      propChange(field, value, _, fapi) {
        if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
          methods.unWatchActiveRule()
          const org = field
          if (field.indexOf('formCreate') === 0) {
            field = field.replace('formCreate', '')
            if (!field) return
            field = lower(field)
            if (field.indexOf('effect') === 0 && field.indexOf('>') > -1) {
              data.activeRule.effect[field.split('>')[1]] = value
            } else if (field.indexOf('props') === 0 && field.indexOf('>') > -1) {
              data.activeRule.props[field.split('>')[1]] = value
            } else if (field.indexOf('attrs') === 0 && field.indexOf('>') > -1) {
              data.activeRule.attrs[field.split('>')[1]] = value
            } else if (field === 'child') {
              data.activeRule.children[0] = value
            } else {
              data.activeRule[field] = value
            }
          } else {
            data.activeRule.props[field] = value
          }
          methods.watchActiveRule()
          data.activeRule.config.config?.watch?.[org]?.({
            field: org,
            value,
            api: fapi,
            rule: data.activeRule
          })
        }
      },
      validateChange(formData) {
        if (!data.activeRule || data.validateForm.api[data.activeRule._id] !== data.activeRule)
          return
        data.activeRule.validate = formData.validate || []
        data.dragForm.api.refreshValidate()
        data.dragForm.api.nextTick(() => {
          data.dragForm.api.clearValidateState(data.activeRule.__fc__.id)
        })
      },
      toolActive(rule) {
        methods.unWatchActiveRule()
        if (data.activeRule) {
          delete data.propsForm.api[data.activeRule._id]
          delete data.baseForm.api[data.activeRule._id]
          delete data.validateForm.api[data.activeRule._id]
          delete data.dragForm.api.activeRule
        }
        data.activeRule = rule
        data.dragForm.api.activeRule = rule

        nextTick(() => {
          data.activeTab = 'props'
          nextTick(() => {
            data.propsForm.api[data.activeRule._id] = data.activeRule
            data.baseForm.api[data.activeRule._id] = data.activeRule
            data.validateForm.api[data.activeRule._id] = data.activeRule
          })
        })
        if (!data.cacheProps[rule._id]) {
          data.cacheProps[rule._id] = tidyRuleConfig(
            rule.config.config.props,
            componentRule.value && componentRule.value[rule.config.config.name],
            rule,
            { t, api: data.dragForm.api }
          ) // rule.config.config.props(rule, {t, api: data.dragForm.api});
        }

        data.propsForm.rule = data.cacheProps[rule._id]
        methods.updateRuleFormData()
        methods.watchActiveRule()
      },
      updateRuleFormData() {
        const rule = data.activeRule
        const formData = { ...rule.props, formCreateChild: deepCopy(rule.children[0]) }
        Object.keys(rule).forEach((k) => {
          if (['effect', 'config', 'payload', 'id', 'type'].indexOf(k) < 0)
            formData['formCreate' + upper(k)] = deepCopy(rule[k])
        })
          ;['props', 'effect', 'attrs'].forEach((name) => {
            rule[name] &&
              Object.keys(rule[name]).forEach((k) => {
                formData['formCreate' + upper(name) + '>' + k] = deepCopy(rule[name][k])
              })
          })
        data.propsForm.value = formData

        data.showBaseRule =
          hasProperty(rule, 'field') &&
          rule.input !== false &&
          (!config.value || config.value.showBaseForm !== false)

        if (data.showBaseRule) {
          data.baseForm.value = {
            field: rule.field,
            title: rule.title || '',
            info: rule.info,
            _control: rule._control
          }
          data.validateForm.value = { validate: rule.validate ? [...rule.validate] : [] }
          data.dragForm.api.refreshValidate()
          data.dragForm.api.nextTick(() => {
            data.dragForm.api.clearValidateState(rule.__fc__.id)
          })
        }
      },
      dragStart(children) {
        data.moveRule = children
        data.added = false
      },
      dragUnchoose(children, evt) {
        data.addRule = {
          children,
          oldIndex: evt.oldIndex
        }
      },
      dragAdd(children, evt) {
        const newIndex = evt.newIndex
        const menu = evt.item._underlying_vm_
        if (!menu || menu.__fc__) {
          if (data.addRule) {
            const rule = data.addRule.children.splice(data.addRule.oldIndex, 1)
            children.splice(newIndex, 0, rule[0])
          }
        } else {
          const rule = methods.makeRule(ruleList[menu.name])
          children.splice(newIndex, 0, rule)
        }
        data.added = true
        // data.dragForm.api.refresh();
      },
      dragEnd(children, { newIndex, oldIndex }) {
        if (!data.added && !(data.moveRule === children && newIndex === oldIndex)) {
          const rule = data.moveRule.splice(oldIndex, 1)
          children.splice(newIndex, 0, rule[0])
        }
        data.moveRule = null
        data.addRule = null
        data.added = false
        // data.dragForm.api.refresh();
      },
      makeRule(config, _rule) {
        const rule = _rule || config.rule({ t })
        rule.config = { config }
        if (config.component) {
          rule.component = markRaw(config.component)
        }
        if (!rule.effect) rule.effect = {}
        rule.effect._fc = true
        rule._fc_drag_tag = config.name

        let drag

        if (config.drag) {
          rule.children.push(
            (drag = methods.makeDrag(config.drag, rule.type, methods.makeChildren([]), {
              end: (inject, evt) => methods.dragEnd(inject.self.children, evt),
              add: (inject, evt) => methods.dragAdd(inject.self.children, evt),
              start: (inject, evt) => methods.dragStart(inject.self.children, evt),
              unchoose: (inject, evt) => methods.dragUnchoose(inject.self.children, evt)
            }))
          )
        }

        if (config.children && !_rule) {
          for (let i = 0; i < (config.childrenLen || 1); i++) {
            const child = methods.makeRule(ruleList[config.children])
              ; (drag || rule).children.push(child)
          }
        }

        const dragMask = mask.value !== undefined ? mask.value !== false : config.mask !== false

        if (config.inside) {
          rule.children = methods.makeChildren([
            {
              type: 'DragTool',
              props: {
                dragBtn: config.dragBtn !== false,
                children: config.children,
                mask: dragMask
              },
              effect: {
                _fc_tool: true
              },
              inject: true,
              on: {
                delete: ({ self }) => {
                  const parent = methods.getParent(self).parent
                  parent.__fc__.rm()
                  vm.emit('delete', parent)
                  methods.clearActiveRule()
                },
                create: ({ self }) => {
                  const top = methods.getParent(self)
                  vm.emit('create', top.parent)
                  top.root.children.splice(
                    top.root.children.indexOf(top.parent) + 1,
                    0,
                    methods.makeRule(top.parent.config.config)
                  )
                },
                addChild: ({ self }) => {
                  const top = methods.getParent(self)
                  const config = top.parent.config.config
                  const item = ruleList[config.children]
                  if (!item) return
                    ; (!config.drag ? top.parent : top.parent.children[0]).children[0].children.push(
                      methods.makeRule(item)
                    )
                },
                copy: ({ self }) => {
                  const top = methods.getParent(self)
                  vm.emit('copy', top.parent)
                  top.root.children.splice(
                    top.root.children.indexOf(top.parent) + 1,
                    0,
                    designerForm.copyRule(top.parent)
                  )
                },
                active: ({ self }) => {
                  const top = methods.getParent(self)
                  vm.emit('active', top.parent)
                  methods.toolActive(top.parent)
                }
              },
              children: rule.children
            }
          ])
          return rule
        } else {
          return {
            type: 'DragTool',
            props: {
              dragBtn: config.dragBtn !== false,
              children: config.children,
              mask: dragMask
            },
            effect: {
              _fc_tool: true
            },
            inject: true,
            on: {
              delete: ({ self }) => {
                vm.emit('delete', self.children[0])
                self.__fc__.rm()
                methods.clearActiveRule()
              },
              create: ({ self }) => {
                vm.emit('create', self.children[0])
                const top = methods.getParent(self)
                top.root.children.splice(
                  top.root.children.indexOf(top.parent) + 1,
                  0,
                  methods.makeRule(self.children[0].config.config)
                )
              },
              addChild: ({ self }) => {
                const config = self.children[0].config.config
                const item = ruleList[config.children]
                if (!item) return
                  ; (!config.drag ? self : self.children[0]).children[0].children.push(
                    methods.makeRule(item)
                  )
              },
              copy: ({ self }) => {
                vm.emit('copy', self.children[0])
                const top = methods.getParent(self)
                top.root.children.splice(
                  top.root.children.indexOf(top.parent) + 1,
                  0,
                  designerForm.copyRule(top.parent)
                )
              },
              active: ({ self }) => {
                vm.emit('active', self.children[0])
                methods.toolActive(self.children[0])
              }
            },
            children: methods.makeChildren([rule])
          }
        }
      }
    }
    data.dragForm.rule = methods.makeDragRule(methods.makeChildren(data.children))
    return {
      ...toRefs(data),
      ...methods,
      dragHeight,
      t
    }
  },
  created() {
    document.body.ondrop = (e) => {
      e.preventDefault()
      e.stopPropagation()
    }
  }
})
</script>

<style lang="scss" scoped>
@import './FormDesigner.scss';
</style>
